
package Network;


import javax.microedition.io.*;
import java.io.*;

import Math.ByteStock;
import Utilities.AlertDialog;

class Identificator
{
  private static int NewIdent = 0;

  static int GetNew( )
  {
    return NewIdent++;
  }
}

/* Start of 'Connection' class */
public class Connection implements Runnable
{
  private SocketConnection Socket = null;
  private InputStream in = null;
  private OutputStream out = null;
  private Thread DataTh = null;
  private ByteStock ByteSt;

  private int Ident;

  public Server SrvRef = null;

  private boolean IsOpen;
  
  /* 'Connection' class constructor
   * ARGUMENTS:
   *   - host to connect
   *       String Host;
   *   - port to connect
   *       int Port;
   * RETURNS: None.
   */
  public Connection( SocketConnection Socket )
  {
      Ident = Identificator.GetNew();
      this.Socket = Socket;
      IsOpen = true;
      InitInOutStreams();
  } /* End of 'Connection' class constructor */
  
  /* 'Connection' class constructor
   * ARGUMENTS:
   *   - host to connect
   *       String Host;
   *   - port to connect
   *       int Port;
   * RETURNS: None.
   */
  public Connection( String Host, int Port )
  {
    Ident = Identificator.GetNew();
    try
    {
      this.Socket = (SocketConnection) Connector.open("socket://" + Host + ":" + Port, Connector.READ_WRITE);
      IsOpen = true;
      InitInOutStreams();
    } catch (IOException ex)
    {
      AlertDialog.ShowError("Server connection failed.", true);
      return;
    }
  } /* End of 'Connection' class constructor */

  /* Output/Input streams initialize function
   * ARGUMENTS: None.
   * RETURNS: None.
   */
  private void InitInOutStreams( )
  {
    try
    {
      in = Socket.openInputStream();
      out = Socket.openOutputStream();
    } catch (IOException ex)
    {
      AlertDialog.ShowError("Input/Output system initialize failed.", true);
      return;
    }
  } /* End of 'InitInOutStreams' function */

  /* Get connection identificator function
   * ARGUMENTS: None.
   * RETURNS:
   *   - Connection identificator
   *       int;
   */
  public final int GetIdent( )
  {
    return Ident;
  } /* End of 'GetIdent' function */

  /* Start incoming data listening function
   * ARGUMENTS: None.
   * RETURNS: None.
   */
  public final void StartListen( )
  {
    if (DataTh == null)
    {
      DataTh = new Thread(this);
      ByteSt = new ByteStock(100);
    }
    if (DataTh.isAlive() == false)
      DataTh.start();
  } /* End of 'StartListen' function */

  /* Stop incoming data listening function
   * ARGUMENTS: None.
   * RETURNS: None.
   */
  public final void StopListen( )
  {
    if (DataTh == null || DataTh.isAlive() == false)
      return;
    DataTh.interrupt();
  } /* End of 'StopListen' function */

  /* Get bytes from server function
   * ARGUMENTS:
   *   - number of bytes to read
   *       int Num;
   * RETURNS:
   *   - byte array readed
   *       byte[];
   */
  public final byte[] GetBytes( int Num )
  {
    return ByteSt.GetBytes(Num);
  } /* End of 'GetBytes' function */

  /* Send bytes to server function
   * ARGUMENTS:
   *   - byte array to send
   *       byte Bytes[];
   *   - number of bytes to send
   *       int Num;
   * RETURNS: None.
   */
  public final boolean SendBytes( byte Bytes[], int Num )
  {
    try
    {
      out.write(Bytes, 0, Num);
    } catch (IOException ex)
    {
      return false;
    }
    return true;
  } /* End of 'SendBytes' function */

  /* Run thread function
   * ARGUMENTS: None.
   * RETURNS: None.
   */
  public final void run( )
  {
    byte Buf[] = null;
    int Num;
    while (true)
    {
      try
      {
        Num = in.read(Buf, 0, 200);
        ByteSt.Add(Buf, Num);

      } catch (IOException ex)
      {
        this.Close();
        return;
      }
    }
  } /* End of 'run' function */

  /* Close connection function
   * ARGUMENTS: None.
   * RETURNS: None.
   */
  public final void Close( )
  {
    IsOpen = false;
    if (SrvRef != null)
      SrvRef.CloseConnection(Ident);
    StopListen();
    try
    {
      if (Socket != null)
        Socket.close();
    } catch (IOException ex)
    {
      return;
    }

    try
    {
      if (in != null)
        in.close();
      if (out != null)
        out.close();
    } catch (IOException ex)
    {
      return;
    }
  } /* End of 'Close' function */

  /* Is connection established function
   * ARGUMENTS: None.
   * RETURNS:
   *   - 'true' - if established, 'false' - otherwice
   *     boolean;
   */
  public boolean IsConnected( )
  {
    return IsOpen;
  } /* End of 'IsConnected' function */
  
} /* End of 'Connection' class */
